
#include "MonsterRefCfg.h"
#include "base/core/os/file.h"
#include "base/core/com_define.h"
#include "base/core/json_parser.h"
#include "Common/Utility/JsonUtility.h"

#include "base/core/log.h"
#include "base/core/random.h"
#include "base/core/gamemath.h"
#include "Scene/MapMgr.h"
#include "Common/TableData/MapMapCfg.h"
#include "Common/TableData/MonsterMonsterCfg.h"
#include "Character/teleporter/TeleporterInfoMgr.h"
#include "Common//TableData/TeleportBornCfg.h"
#include "Common/TableData/AreaAreaCfg.h"
#include "Common/TableData/NpcNpcCfg.h"
#include "Common/TableData/BattlenpcBattlenpcCfg.h"

#include <sstream>
#include <fstream>

MapLoactionCfg::MapLoactionCfg()
{
	m_monsterGroupRefMap.clear();
	m_npcRefLoc.clear();
	m_teleporterLoc.clear();
	m_collectLoc.clear();
	m_areaRefLoc.clear();
	m_bornRefLoc.clear();
	m_monsterRefMap.clear();
	m_blockRefMap.clear();
}

MapLoactionCfg::~MapLoactionCfg()
{

}

bool MapLoactionCfg::Init()
{
	bool result = false;
	bool retCode = true;

	std::string dir = "./data/json/";
	std::string endwith = ".json";
	uint32_t mapId;		//地图id
	const MapMapCfgMap *mapConfig;
	char buffer[64];
	memset(buffer, 0, 64);

	mapConfig = g_GetMapMapCfgTable()->GetMapMapCfgMap();
	if (mapConfig != nullptr)
	{
		MapMapCfgMap::const_iterator it;
		for (it = mapConfig->begin(); it != mapConfig->end(); ++it)
		{
			mapId = it->second.mapId;
			snprintf(buffer, 64, "%d", mapId);
			retCode = LoadConfig(dir + buffer + endwith);
			MMOLOG_PROCESS_ERROR(retCode);
		}
	}

	//必须在地图加载后面，场景加载前面
	MMOLOG_PROCESS_ERROR(g_MakeTeleporterInfoMgr());
	if (!g_GetTeleporterInfoMgr()->Init())
	{
		LogErrPrint("[logic] teleporter info mgr init fail");
		goto Exit0;
	}

	result = true;
Exit0:
	return result;
}

bool MapLoactionCfg::LoadConfig(const std::string& cfgFile)
{
	if (File::IsFileExist(cfgFile.c_str()) == false)
	{
		return true;
	}
	
	File* file = FileOpen(cfgFile.c_str(), "rb");
	if (file == nullptr)
	{
		LogErrFmtPrint("map location config file:%s FileOpen failed", cfgFile.c_str());
		return false;
	}

	size_t size = file->GetSize();
	
	char* buffer = new char[size + 1];
	if (buffer == nullptr)
	{
		LogErrFmtPrint("map location config file:%s new buffer failed", cfgFile.c_str());
		return false;
	}

	file->Read(buffer, size);
	buffer[size] = '\0';
	
	FileClose(file);
	file = nullptr;

	rapidjson::Document doc;
	doc.Parse(buffer);

	MMO_DELETE_ARRAY(buffer);

	if (doc.HasParseError())
	{
		LogErrFmtPrint("map location config file:%s file parese failed:%d", cfgFile.c_str(), doc.GetParseError());
		return false;
	}
	
	if (doc.HasMember("mapID") == false || doc["mapID"].IsInt() == false)
	{
		LogErrFmtPrint("map location config file:%s init failed, mapID is not exist!", cfgFile.c_str());
		return false;
	}

	uint32_t mapId = doc["mapID"].GetInt();

	if (g_GetMapMgr()->GetMap(mapId) == nullptr)
	{
		LogErrFmtPrint("map location config file:%s init failed, mapID:%d is can't finded in the map mgr!", cfgFile.c_str(), mapId);
		return false;
	}

	if (doc.HasMember("monster") == true && doc["monster"].IsArray() == true)
	{
		for (rapidjson::SizeType i = 0; i < doc["monster"].Size(); i++)
		{
			rapidjson::Value& monster = doc["monster"][i];
			if (monster.HasMember("id") == false || monster["id"].IsInt() == false)
			{
				LogErrFmtPrint("map location config file:%s init failed, monster id is not exist or is not int", cfgFile.c_str());
				return false;
			}

			if (monster.HasMember("pos") == false || monster["pos"].IsArray() == false || 
				monster["pos"].Size() != 3)
			{
				LogErrFmtPrint("map location config file:%s init failed, monster pos is not exist or is not int", cfgFile.c_str());
				return false;
			}

			if (monster.HasMember("scale") == false || monster["scale"].IsArray() == false ||
				monster["scale"].Size() != 3)
			{
				LogErrFmtPrint("map location config file:%s init failed, monster scale is not exist or is not int", cfgFile.c_str());
				return false;
			}

			if (monster.HasMember("rotate") == false || monster["rotate"].IsArray() == false ||
				monster["rotate"].Size() != 3)
			{
				LogErrFmtPrint("map location config file:%s init failed, monster rotate is not exist or is not int", cfgFile.c_str());
				return false;
			}

			/*
			if (monster.HasMember("positionX") == false || monster["positionX"].IsDouble() == false)
			{
				LogErrFmtPrint("map location config file:%s init failed, monster positionX is not exist or is not double", cfgFile.c_str());
				return false;
			}

			if (monster.HasMember("positionY") == false || monster["positionX"].IsDouble() == false)
			{
				LogErrFmtPrint("map location config file:%s init failed, monster positionY is not exist or is not double", cfgFile.c_str());
				return false;
			}

			if (monster.HasMember("positionZ") == false || monster["positionX"].IsDouble() == false)
			{
				LogErrFmtPrint("map location config file : %s init failed, monster positionZ is not exist or is not double", cfgFile.c_str());
				return false;
			}
			*/

			if (monster.HasMember("group") == false || monster["group"].IsInt() == false)
			{
				LogErrFmtPrint("map location config file:%s init failed, monster:group is not exist or is not int", cfgFile.c_str());
				return false;
			}

			if (monster.HasMember("fresh") == false || monster["fresh"].IsInt() == false)
			{
				LogErrFmtPrint("map location config file:%s init failed, monster:fresh is not exist or is not int", cfgFile.c_str());
				return false;
			}
		}

		for (rapidjson::SizeType i = 0; i < doc["monster"].Size(); i++)
		{
			rapidjson::Value& monster = doc["monster"][i];

			int group = monster["group"].GetInt();
			int fresh = monster["fresh"].GetInt();
			int monsterId = monster["id"].GetInt();

			const MonsterMonsterCfgInfo *pMonsterCfg = g_GetMonsterMonsterCfgTable()->GetMonsterMonsterCfgInfo(monsterId);
			if (pMonsterCfg == nullptr)
			{
				LogErrFmtPrint("map location config file:%s init failed, monster id:%u is not exist", cfgFile.c_str(), monsterId);
				return false;
			}

			MonsterRefLocation refLoc;
			refLoc.m_RefLocIndex = i;
			refLoc.m_id = monsterId;
			refLoc.m_internalTime = pMonsterCfg->monsterRefreshTime;
			refLoc.m_bornPos.x = (float)monster["pos"][0].GetDouble();
			refLoc.m_bornPos.y = (float)monster["pos"][1].GetDouble();
			refLoc.m_bornPos.z = (float)monster["pos"][2].GetDouble();
			refLoc.m_scale.x = (float)monster["scale"][0].GetDouble();
			refLoc.m_scale.y = (float)monster["scale"][1].GetDouble();
			refLoc.m_scale.z = (float)monster["scale"][2].GetDouble();
			refLoc.m_dir.x = (float)monster["rotate"][0].GetDouble();
			refLoc.m_dir.y = (float)monster["rotate"][1].GetDouble();
			refLoc.m_dir.z = (float)monster["rotate"][2].GetDouble();
			refLoc.m_deadTime = 0;
			refLoc.m_fresh = fresh;
			refLoc.m_group = group;

			m_monsterGroupRefMap[mapId][group].push_back(refLoc);

			//
			monsterGroupRefMap::iterator iterMap = m_monsterRefMap.find(mapId);
			if (iterMap != m_monsterRefMap.end())
			{
				MonsterRefLocationMap &mapMonster = iterMap->second;
				MonsterRefLocationMap::iterator iterRef = mapMonster.find(refLoc.m_id);
				if (iterRef != mapMonster.end())
				{
					iterRef->second.push_back(refLoc);
				}
				else
				{
					std::vector<MonsterRefLocation> vecRef;
					vecRef.clear();
					vecRef.push_back(refLoc);
					mapMonster[refLoc.m_id] = vecRef;
				}				
			}
			else
			{
				std::vector<MonsterRefLocation> vecRef;
				vecRef.clear();
				MonsterRefLocationMap mapRef;
				mapRef.clear();
				//
				vecRef.push_back(refLoc);
				mapRef[refLoc.m_id] = vecRef;
				m_monsterRefMap[mapId] = mapRef;
			}
		}
	}

	if (doc.HasMember("teleporter") == true && doc["teleporter"].IsArray() == true)
	{
		for (rapidjson::SizeType i = 0; i < doc["teleporter"].Size(); i++)
		{
			rapidjson::Value& teleporter = doc["teleporter"][i];
			if (teleporter.HasMember("id") == false || teleporter["id"].IsInt() == false)
			{
				LogErrFmtPrint("map location config file:%s init failed, teleporter id is not exist or is not int", cfgFile.c_str());
				return false;
			}

			if (teleporter.HasMember("pos") == false || teleporter["pos"].IsArray() == false ||
				teleporter["pos"].Size() != 3)
			{
				LogErrFmtPrint("map location config file:%s init failed, teleporter pos is not exist or is not int", cfgFile.c_str());
				return false;
			}

			if (teleporter.HasMember("stand") == false || teleporter["stand"].IsArray() == false ||
				teleporter["stand"].Size() != 3)
			{
				LogErrFmtPrint("map location config file:%s init failed, teleporter stand is not exist or is not int", cfgFile.c_str());
				return false;
			}

			/*
			if (teleporter.HasMember("positionX") == false || teleporter["positionX"].IsDouble() == false)
			{
				LogErrFmtPrint("map location config file:%s init failed, teleporter positionX is not exist or is not double", cfgFile.c_str());
				return false;
			}

			if (teleporter.HasMember("positionY") == false || teleporter["positionX"].IsDouble() == false)
			{
				LogErrFmtPrint("map location config file:%s init failed, teleporter positionY is not exist or is not double", cfgFile.c_str());
				return false;
			}

			if (teleporter.HasMember("positionZ") == false || teleporter["positionX"].IsDouble() == false)
			{
				LogErrFmtPrint("map location config file : %s init failed, teleporter positionZ is not exist or is not double", cfgFile.c_str());
				return false;
			}
			*/
		}

		for (rapidjson::SizeType i = 0; i < doc["teleporter"].Size(); i++)
		{
			rapidjson::Value& teleporter = doc["teleporter"][i];

			TeleporterLocation refLoc;
			refLoc.m_id = teleporter["id"].GetInt();
			refLoc.m_pos.x = (float)teleporter["pos"][0].GetDouble();
			refLoc.m_pos.y = (float)teleporter["pos"][1].GetDouble();
			refLoc.m_pos.z = (float)teleporter["pos"][2].GetDouble();
			refLoc.m_transPos.x = (float)teleporter["stand"][0].GetDouble();
			refLoc.m_transPos.y = (float)teleporter["stand"][1].GetDouble();
			refLoc.m_transPos.z = (float)teleporter["stand"][2].GetDouble();
			refLoc.m_mapid = mapId;
			m_teleporterLoc[refLoc.m_id] = refLoc;
		}
	}

	if (doc.HasMember("npc") == true && doc["npc"].IsArray() == true)
	{
		for (rapidjson::SizeType i = 0; i < doc["npc"].Size(); i++)
		{
			rapidjson::Value& npc = doc["npc"][i];
			if (npc.HasMember("id") == false || npc["id"].IsInt() == false)
			{
				LogErrFmtPrint("map location config file:%s init failed, npc id is not exist or is not int", cfgFile.c_str());
				return false;
			}

			if (npc.HasMember("pos") == false || npc["pos"].IsArray() == false ||
				npc["pos"].Size() != 3)
			{
				LogErrFmtPrint("map location config file:%s init failed, npc pos is not exist or is not int", cfgFile.c_str());
				return false;
			}
			/*
			if (npc.HasMember("positionX") == false || npc["positionX"].IsDouble() == false)
			{
				LogErrFmtPrint("map location config file:%s init failed, npc positionX is not exist or is not double", cfgFile.c_str());
				return false;
			}

			if (npc.HasMember("positionY") == false || npc["positionX"].IsDouble() == false)
			{
				LogErrFmtPrint("map location config file:%s init failed, npc positionY is not exist or is not double", cfgFile.c_str());
				return false;
			}

			if (npc.HasMember("positionZ") == false || npc["positionX"].IsDouble() == false)
			{
				LogErrFmtPrint("map location config file : %s init failed, npc positionZ is not exist or is not double", cfgFile.c_str());
				return false;
			}
			*/
		}

		for (rapidjson::SizeType i = 0; i < doc["npc"].Size(); i++)
		{
			rapidjson::Value& npc = doc["npc"][i];

			NPCRefLocation refLoc;
			refLoc.m_id = npc["id"].GetInt();
			refLoc.m_internalTime = 0;
			refLoc.m_bornPos.x = (float)npc["pos"][0].GetDouble();
			refLoc.m_bornPos.y = (float)npc["pos"][1].GetDouble();
			refLoc.m_bornPos.z = (float)npc["pos"][2].GetDouble();
			refLoc.m_RefLocIndex = i;

			//npc配置
			const NpcNpcCfgInfo *pNpcCfg = g_GetNpcNpcCfgTable()->GetNpcNpcCfgInfo(refLoc.m_id);
			if (nullptr == pNpcCfg)
			{
				LogErrFmtPrint("map location config file : %s init failed, npc:%u  not exists...", cfgFile.c_str(), refLoc.m_id);
				return false;
			}
			if (pNpcCfg->linkBattlenpc > 0) //如果是战斗npc需要取的战斗npc配置中的死亡复活时间
			{
				const BattlenpcBattlenpcCfgInfo *pBattleNpcCfg = g_GetBattlenpcBattlenpcCfgTable()->GetBattlenpcBattlenpcCfgInfo(pNpcCfg->linkBattlenpc);
				if (nullptr != pBattleNpcCfg)
				{
					refLoc.m_internalTime = pBattleNpcCfg->npcRefreshTime;
				}
				else
				{
					LogErrFmtPrint("map location config file : %s , can not find npc:%u  battle data.... linkBattlenpc:%u ", cfgFile.c_str(), refLoc.m_id,pNpcCfg->linkBattlenpc);
				}
			}

			m_npcRefLoc[mapId].push_back(refLoc);
		}
	}

	if (doc.HasMember("born") && doc["born"].IsArray() == true)
	{
		for (rapidjson::SizeType i = 0; i < doc["born"].Size(); i++)
		{
			rapidjson::Value& born = doc["born"][i];

			if (born.HasMember("id") == false || born["id"].IsInt() == false)
			{
				LogErrFmtPrint("map location config file:%s init failed, born id is not exist or is not int", cfgFile.c_str());
				return false;
			}

			if (born.HasMember("pos") == false || born["pos"].IsArray() == false ||
				born["pos"].Size() != 3)
			{
				LogErrFmtPrint("map location config file:%s init failed, born pos is not exist or is not int", cfgFile.c_str());
				return false;
			}
		}

		for (rapidjson::SizeType i = 0; i < doc["born"].Size(); i++)
		{
			rapidjson::Value& born = doc["born"][i];

			BornRefLocation refLoc;
			refLoc.m_nBornId = born["id"].GetInt();
			refLoc.m_pos.x = (float)born["pos"][0].GetDouble();
			refLoc.m_pos.y = (float)born["pos"][1].GetDouble();
			refLoc.m_pos.z = (float)born["pos"][2].GetDouble();

			m_bornRefLoc[mapId].push_back(refLoc);
		}
	}

	if (doc.HasMember("area") && doc["area"].IsArray() == true)
	{
		for (rapidjson::SizeType i = 0; i < doc["area"].Size(); i++)
		{
			rapidjson::Value& born = doc["area"][i];

			if (born.HasMember("id") == false || born["id"].IsInt() == false)
			{
				LogErrFmtPrint("map location config file:%s init failed, area id is not exist or is not int", cfgFile.c_str());
				return false;
			}

			if (born.HasMember("radius") == false || born["radius"].IsDouble() == false)
			{
				LogErrFmtPrint("map location config file:%s init failed, area radius id is not exist or is not double", cfgFile.c_str());
				return false;
			}

			if (born.HasMember("point") == false || born["point"].IsArray() == false ||
				born["point"].Size() < 1)
			{
				LogErrFmtPrint("map location config file:%s init failed,  area point is not exist or is not int", cfgFile.c_str());
				return false;
			}

			for (rapidjson::SizeType j = 0; j < born["point"].Size(); j++)
			{
				rapidjson::Value& point = born["point"][j];
				if (point.Size() < 3)
				{
					LogErrFmtPrint("map location config file:%s init failed, area point.Size() < 3....", cfgFile.c_str());
					return false;
				}
			}
		}

		if (doc["area"].Size() > 0)
		{
			std::unordered_map<uint32_t, AreaRefLocation> mapArea;
			mapArea.clear();
			for (rapidjson::SizeType i = 0; i < doc["area"].Size(); i++)
			{
				rapidjson::Value& born = doc["area"][i];
				//
				uint32_t area_id = born["id"].GetInt();
				std::unordered_map<uint32_t, AreaRefLocation>::iterator iterArea = mapArea.find(area_id);
				if (iterArea != mapArea.end())
				{
					LogErrFmtPrint("map location config file:%s init failed, repeated areaid....area_id:%u ", cfgFile.c_str(), area_id);
				}

				AreaRefLocation refLoc;
				refLoc.m_nAreaId = born["id"].GetInt();
				refLoc.m_radius = (float)born["radius"].GetDouble();
				for (rapidjson::SizeType j = 0; j < born["point"].Size(); j++)
				{
					rapidjson::Value& point = born["point"][j];
					Point3<float> pos;
					pos.x = (float)point[0].GetDouble();
					pos.y = (float)point[1].GetDouble();
					pos.z = (float)point[2].GetDouble();
					refLoc.m_vecPos.push_back(pos);
				}
				mapArea[refLoc.m_nAreaId] = refLoc;
			}
			m_areaRefLoc[mapId] = mapArea;
		}
		
	}

	if (doc.HasMember("collect") && doc["collect"].IsArray() == true)
	{
		for (rapidjson::SizeType i = 0; i < doc["collect"].Size(); i++)
		{
			rapidjson::Value& collect = doc["collect"][i];

			if (collect.HasMember("id") == false || collect["id"].IsInt() == false)
			{
				LogErrFmtPrint("map location config file:%s init failed, area id is not exist or is not int", cfgFile.c_str());
				return false;
			}


			if (collect.HasMember("point") == false || collect["point"].IsArray() == false
				|| collect["point"].Size() < 1)
			{
				LogErrFmtPrint("map location config file:%s init failed,  collect point is not exist or is not array", cfgFile.c_str());
				return false;
			}

			CollectRefLocation collectRef;
			collectRef.m_collectId = collect["id"].GetInt();
			for (rapidjson::SizeType j = 0; j < collect["point"].Size(); j++)
			{
				rapidjson::Value& point = collect["point"][j];
				Point3<float> pos;
				pos.x = (float)point[0].GetDouble();
				pos.y = (float)point[1].GetDouble();
				pos.z = (float)point[2].GetDouble();
				collectRef.m_vecPos.push_back(pos);
			}

			collectLocationMap::iterator iter = m_collectLoc.find(collectRef.m_collectId);
			if (iter != m_collectLoc.end())
			{
				LogErrFmtPrint("map location config file:%s init failed,  collect id[%u] already exist ", cfgFile.c_str(), collectRef.m_collectId);
				return false;
			}
			m_collectLoc[collectRef.m_collectId] = collectRef;
		}
	}

	if (doc.HasMember("path") && doc["path"].IsArray() == true)
	{
		for (rapidjson::SizeType i = 0; i < doc["path"].Size(); i++)
		{
			rapidjson::Value& path = doc["path"][i];
			if (path.HasMember("id") == false || path["id"].IsInt() == false)
			{
				LogErrFmtPrint("map location config file:%s init failed, path id is not exist or is not int", cfgFile.c_str());
				return false;
			}

			if (path.HasMember("point") == false || path["point"].IsArray() == false
				|| path["point"].Size() < 1)
			{
				LogErrFmtPrint("map location config file:%s init failed,  path point is not exist or is not array", cfgFile.c_str());
				return false;
			}

			PathRefLocation pathRef;
			pathRef.m_mapId = mapId;
			pathRef.m_id = path["id"].GetInt();
			for (rapidjson::SizeType j = 0; j < path["point"].Size(); j++)
			{
				rapidjson::Value& point = path["point"][j];
				Point3<float> pos;
				pos.x = (float)point[0].GetDouble();
				pos.y = (float)point[1].GetDouble();
				pos.z = (float)point[2].GetDouble();
				pathRef.m_vecPos.push_back(pos);
			}

			PathLocationMap::iterator iter = m_pathLoc.find(pathRef.m_id);
			if (iter != m_pathLoc.end())
			{
				LogErrFmtPrint("map location config file:%s init failed,  path id[%u] already exist ", cfgFile.c_str(), pathRef.m_id);
				return false;
			}
			m_pathLoc[pathRef.m_id] = pathRef;
		}
	}

	if (doc.HasMember("block") && doc["block"].IsArray() == true)
	{
		for (rapidjson::SizeType i = 0; i < doc["block"].Size(); i++)
		{
			rapidjson::Value& block = doc["block"][i];
			if (block.HasMember("id") == false || block["id"].IsInt() == false)
			{
				LogErrFmtPrint("map location config file:%s init failed, block id is not exist or is not int", cfgFile.c_str());
				return false;
			}

			if (block.HasMember("pos") == false || block["pos"].IsArray() == false
				|| block["pos"].Size() < 3)
			{
				LogErrFmtPrint("map location config file:%s init failed,  block pos is not exist or is not array", cfgFile.c_str());
				return false;
			}

			BlockRefLocation blockLoc;
			blockLoc.m_blockId = block["id"].GetUint();
			blockLoc.m_pos.x = (float)block["pos"][0].GetDouble();
			blockLoc.m_pos.y = (float)block["pos"][1].GetDouble();
			blockLoc.m_pos.z = (float)block["pos"][2].GetDouble();

			blockLocationMap::iterator iter = m_blockRefMap.find(blockLoc.m_blockId);
			if (iter != m_blockRefMap.end())
			{
				LogErrFmtPrint("map location config file:%s init failed,  block id[%u] already exist ", cfgFile.c_str(), blockLoc.m_blockId);
				return false;
			}
			m_blockRefMap[blockLoc.m_blockId] = blockLoc;
		}
	}

	return true;
}

bool MapLoactionCfg::UnInit()
{
	m_monsterGroupRefMap.clear();
	m_npcRefLoc.clear();
	m_teleporterLoc.clear();
	m_collectLoc.clear();
	m_areaRefLoc.clear();
	m_bornRefLoc.clear();
	m_monsterRefMap.clear();
	m_blockRefMap.clear();
	return true;
}

bool MapLoactionCfg::isExistMapId(uint32_t mapId)
{
	if (m_monsterGroupRefMap.find(mapId) == m_monsterGroupRefMap.end())
	{
		return false;
	}
	return true;
}

MapLoactionCfg::MonsterRefLocationMap* MapLoactionCfg::getMonsterRefMap(uint32_t mapId)
{
	monsterGroupRefMap::iterator it = m_monsterGroupRefMap.find(mapId);
	if (it != m_monsterGroupRefMap.end())
	{
		return &(it->second);
	}

	return nullptr;
}

const vector<MonsterRefLocation> *MapLoactionCfg::GetMonsterRef(uint32_t mapId, uint32_t monsterId)
{
	monsterGroupRefMap::iterator iter = m_monsterRefMap.find(mapId);
	if (iter != m_monsterRefMap.end())
	{
		MonsterRefLocationMap &mapMonster = iter->second;
		MonsterRefLocationMap::iterator iterRef = mapMonster.find(monsterId);
		return (iterRef != mapMonster.end()) ? &iterRef->second : nullptr;
	}
	return nullptr;
}

const MapLoactionCfg::MonsterRefLocationMap *MapLoactionCfg::getMonsRefMap(uint32_t mapId)
{
	monsterGroupRefMap::iterator iter = m_monsterRefMap.find(mapId);
	return (iter != m_monsterRefMap.end()) ? &iter->second : nullptr;
}

const MonsterRefLocation* MapLoactionCfg::GetRndomMonsterRef(uint32_t mapId, uint32_t monsterId)
{
	monsterGroupRefMap::iterator iter = m_monsterRefMap.find(mapId);
	if (iter != m_monsterRefMap.end())
	{
		MonsterRefLocationMap &mapMonster = iter->second;
		MonsterRefLocationMap::iterator iterRef = mapMonster.find(monsterId);
		if (iterRef != mapMonster.end())
		{
			uint32_t size = iterRef->second.size();
			uint32_t index = Random(0, size - 1);
			if (index >= size)
			{
				return nullptr;
			}

			return &(iterRef->second.at(index));
		}
	}

	return nullptr;
}

std::vector<NPCRefLocation>* MapLoactionCfg::getNPCRefLoc(uint32_t mapId)
{
	NPCRefLocationMap::iterator it = m_npcRefLoc.find(mapId);
	if (it != m_npcRefLoc.end())
	{
		return &(it->second);
	}

	return nullptr;
}

TeleporterLocation* MapLoactionCfg::getTeleporterLocation(uint32_t teleporterId)
{
	teleporterLocationMap::iterator it = m_teleporterLoc.find(teleporterId);
	if (it != m_teleporterLoc.end())
	{
		return &(it->second);
	}

	return nullptr;
}

Point3<float>  MapLoactionCfg::GetFirstTeleportPos(uint32_t mapID)
{
	std::vector<uint32_t> vecId;
	getAllTeleporterId(vecId);
	for (int i = 0; i < (int)vecId.size();++i)
	{
		TeleporterLocation* pTelepor=getTeleporterLocation(vecId[i]);
		if (pTelepor)
		{
			if (pTelepor->m_mapid ==mapID)
			{
				return pTelepor->m_transPos;
			}
		}
	}

	return Point3<float>(0, 0, 0);
}

void MapLoactionCfg::getAllTeleporterId(std::vector<uint32_t>& vecId)
{
	teleporterLocationMap::iterator it = m_teleporterLoc.begin();
	for (; it != m_teleporterLoc.end(); it++)
	{
		vecId.push_back(it->first);
	}
}

uint32_t MapLoactionCfg::GetMapGroupMonsterCount(uint32_t mapId, uint32_t groupId, uint32_t monsterId)
{
	if (m_monsterGroupRefMap.find(mapId) != m_monsterGroupRefMap.end())
	{
		if (m_monsterGroupRefMap[mapId].find(groupId) != m_monsterGroupRefMap[mapId].end())
		{
			uint32_t count = 0;
			std::vector<MonsterRefLocation>& vec = m_monsterGroupRefMap[mapId][groupId];
			for (size_t i = 0; i < vec.size(); i++)
			{
				if (vec[i].m_id == monsterId)
				{
					count++;
				}
			}
			return count;
		}
	}
	return 0;
}

const std::vector<MonsterRefLocation>* MapLoactionCfg::GetMapGroupMonster(uint32_t mapId, uint32_t groupId)
{
	if (m_monsterGroupRefMap.find(mapId) != m_monsterGroupRefMap.end())
	{
		if (m_monsterGroupRefMap[mapId].find(groupId) != m_monsterGroupRefMap[mapId].end())
		{
			return &m_monsterGroupRefMap[mapId][groupId];
		}
	}
	return nullptr;
}

const std::vector<BornRefLocation> *MapLoactionCfg::GetMapBornLocation(uint32_t mapId)
{
	BornRefLocationMap::const_iterator iter = m_bornRefLoc.find(mapId);
	return (iter != m_bornRefLoc.end()) ? &iter->second : nullptr;
}

const BornRefLocation *MapLoactionCfg::GetMapBornLocation(uint32_t mapId, uint32_t bornId)
{
	const std::vector<BornRefLocation> *pVecMapBorn = GetMapBornLocation(mapId);
	if (nullptr != pVecMapBorn)
	{
		vector<BornRefLocation>::const_iterator iter = pVecMapBorn->begin();
		for (; iter != pVecMapBorn->end(); ++iter)
		{
			const BornRefLocation &bornLoc = (*iter);
			if (bornId == bornLoc.m_nBornId)
			{
				return &bornLoc;
			}
		}
	}
	return nullptr;
}

const BornRefLocation *MapLoactionCfg::RandBornLocation(uint32_t mapId)
{
	const BornRefLocation *pBornRefLocation = nullptr;
	const std::vector<BornRefLocation> *pVecBorn = GetMapBornLocation(mapId);
	if (nullptr != pVecBorn && pVecBorn->size() > 0)
	{
		int32_t idx = Random((uint32_t)pVecBorn->size());
		pBornRefLocation = &pVecBorn->at(idx);
	}

	return pBornRefLocation;
}

int32_t MapLoactionCfg::GetBornLocationCount(uint32_t mapId)
{
	const std::vector<BornRefLocation> *pVecBorn = GetMapBornLocation(mapId);
	if (nullptr != pVecBorn)
	{
		return (int32_t)pVecBorn->size();
	}
	return 0;
}

const BornRefLocation *MapLoactionCfg::GetBornLocationByIdx(uint32_t mapId,int32_t idx)
{
	const BornRefLocation *pBornRefLocation = nullptr;
	const std::vector<BornRefLocation> *pVecBorn = GetMapBornLocation(mapId);
	if (nullptr != pVecBorn)
	{
		if (idx >= 0 && idx < (int32_t)pVecBorn->size())
		{
			pBornRefLocation = &pVecBorn->at(idx);
		}
	}
	return pBornRefLocation;
}

const AreaRefLocation* MapLoactionCfg::GetAreaRefLoc(uint32_t mapId, uint32_t nAreaId)
{
	AreaRefLocationMap::const_iterator iter = m_areaRefLoc.find(mapId);
	if (iter != m_areaRefLoc.end())
	{
		const std::unordered_map<uint32_t, AreaRefLocation> &areaMap = iter->second;
		std::unordered_map<uint32_t, AreaRefLocation>::const_iterator iterFind = areaMap.find(nAreaId);
		return (iterFind != areaMap.end()) ? &iterFind->second : nullptr;
	}
	return  nullptr;
}
//获取该地图的所有区域ID
void  MapLoactionCfg::GetAreaIdByMap(uint32_t mapid, std::vector<uint32_t> &vID)
{
	AreaRefLocationMap::const_iterator iter = m_areaRefLoc.find(mapid);
	if (iter!=m_areaRefLoc.end())
	{
		std::unordered_map<uint32_t, AreaRefLocation>::const_iterator iterArea = iter->second.begin();
		for (;iterArea!=iter->second.end();++iterArea)
		{
			vID.push_back(iterArea->first);
		}
	}
}

//获取该地图的所有安全区域ID
void MapLoactionCfg::GetSafeAreaIdByMap(uint32_t mapid, int32_t safeType, std::vector<uint32_t> &vID)
{
	AreaRefLocationMap::const_iterator iter = m_areaRefLoc.find(mapid);
	if (iter != m_areaRefLoc.end())
	{
		std::unordered_map<uint32_t, AreaRefLocation>::const_iterator iterArea = iter->second.begin();
		for (; iterArea != iter->second.end(); ++iterArea)
		{
			const AreaAreaCfgInfo *pAreaCfg = g_GetAreaAreaCfgTable()->GetAreaAreaCfgInfo(iterArea->first);
			if (nullptr == pAreaCfg)	continue;
			//中立
			if (safeType == 1 && pAreaCfg->safeAreaType > 0)
			{
				vID.push_back(iterArea->first);
				continue;
			}
			//光明
			if (safeType == 2 && (pAreaCfg->safeAreaType == 1 || pAreaCfg->safeAreaType == 2))
			{
				vID.push_back(iterArea->first);
				continue;
			}
			//黑暗
			if (safeType == 3 && (pAreaCfg->safeAreaType == 1 || pAreaCfg->safeAreaType == 3))
			{
				vID.push_back(iterArea->first);
			}
		}
	}
}

//获取阻挡信息
const BlockRefLocation *MapLoactionCfg::GetBlockRefLoc(uint32_t blockId)
{
	blockLocationMap::iterator iter = m_blockRefMap.find(blockId);
	return (iter != m_blockRefMap.end()) ? &iter->second : nullptr;
}
bool MapLoactionCfg::InArea(uint32_t areaId, Point3<float> pos)
{
	const AreaAreaCfgInfo *pAreaCfg = g_GetAreaAreaCfgTable()->GetAreaAreaCfgInfo(areaId);
	if (nullptr != pAreaCfg)
	{
		const AreaRefLocation *pAreaRefLoc = GetAreaRefLoc(pAreaCfg->belongToSceneID, areaId);
		if (nullptr != pAreaRefLoc)
		{
			if (EMapAreaType_Quadrangle == pAreaCfg->shapeType)
			{
				if (pAreaRefLoc->m_vecPos.size() >= 5)
				{
					Point3<float> a = pAreaRefLoc->m_vecPos.at(1);
					Point3<float> b = pAreaRefLoc->m_vecPos.at(2);
					Point3<float> c = pAreaRefLoc->m_vecPos.at(3);
					Point3<float> d = pAreaRefLoc->m_vecPos.at(4);

					/*if (370110101 == areaId)
					{
						Point3<float> p = pos;
						float dTriangle = triangleArea(a, b, p) + triangleArea(b, c, p) + triangleArea(c, d, p) + triangleArea(d, a, p);
						float dQuadrangle = triangleArea(a, b, c) + triangleArea(c, d, a);
						LogDebugFmtPrint("[logic] area calcluate.....dTriangle:%f, dQuadrangle:%f, [%f,%f,%f], [%f,%f,%f], [%f,%f,%f], [%f,%f,%f], [%f,%f,%f]", dTriangle,dQuadrangle,a.x,a.y,a.z,b.x,b.y,b.z,c.x,c.y,c.z,d.x,d.y,d.z,p.x,p.y,p.z);
					}
					*/

					return isInRect(a, b, c, d, pos);
				}
			}
			else if (EMapAreaType_Circle == pAreaCfg->shapeType)
			{
				if (pAreaRefLoc->m_vecPos.size() >= 1)
				{
					const Point3<float> &mid = pAreaRefLoc->m_vecPos.at(0);
					//
					return isInCircle(mid, pAreaRefLoc->m_radius, pos);
				}
			}
		}
	}

	return false;
}


Point3<float> MapLoactionCfg::GetNearRelivePos(uint32_t mapid, Point3<float> & currentPos, uint32_t cmap)
{
	uint32_t minDistance = 100000000;
	uint32_t minZhongLiDistance = 100000000;
	Point3<float> nearPos = Point3<float>(0, 0, 0);
	Point3<float> nearZhongLiPos = Point3<float>(0, 0, 0);
	//先找到该图出身点信息
	BornRefLocationMap::iterator iter = m_bornRefLoc.find(mapid);
	if (iter!=m_bornRefLoc.end())
	{
		for (int i = 0; i < (int)iter->second.size();++i)
		{
			const TeleportBornCfgInfo * pBornConfig=g_GetTeleportBornCfgTable()->GetTeleportBornCfgInfo(iter->second.at(i).m_nBornId);
			if (pBornConfig)
			{
				if ((uint32_t)pBornConfig->camp==cmap)
				{
					uint32_t distance = (uint32_t)point3Length(currentPos, iter->second.at(i).m_pos);
					if (distance<minDistance)
					{
						nearPos = iter->second.at(i).m_pos;
					}
				}

				if (pBornConfig->camp==0)
				{
					uint32_t distance = point3Length(currentPos, iter->second.at(i).m_pos);
					if (distance < minZhongLiDistance)
					{
						nearZhongLiPos = iter->second.at(i).m_pos;
					}
				}
			}
		}
	}

	if (nearPos.length()<=0)
	{
		nearPos = nearZhongLiPos;
	}

	return nearPos;
}


Point3<float> MapLoactionCfg::RandPosInArea(uint32_t areaId)
{
	Point3<float> destPos(0.0f, 0.0f, 0.0f);
	const AreaAreaCfgInfo *pAreaCfg = g_GetAreaAreaCfgTable()->GetAreaAreaCfgInfo(areaId);
	if (nullptr != pAreaCfg)
	{
		Map* pMap = g_GetMapMgr()->GetMap(pAreaCfg->belongToSceneID);
		const AreaRefLocation *pAreaRefLoc = GetAreaRefLoc(pAreaCfg->belongToSceneID, areaId);
		if (nullptr != pAreaRefLoc && nullptr != pMap)
		{
			if (EMapAreaType_Quadrangle == pAreaCfg->shapeType) //矩形 [标志位置，左上角，右上角，右下角，左下角]
			{
				if (pAreaRefLoc->m_vecPos.size() >= 5)
				{
					//Point3<float> l_top = pAreaRefLoc->m_vecPos.at(1);
					Point3<float> r_top = pAreaRefLoc->m_vecPos.at(2);
					//Point3<float> r_buttom = pAreaRefLoc->m_vecPos.at(3);
					Point3<float> l_buttom = pAreaRefLoc->m_vecPos.at(4);
					//暂时取对角线上的随机一个点作为随机坐标
					float f_coef = (float)(Random(1, 1000)) / 1000.0f;
					float fnew_x = l_buttom.x + (r_top.x - l_buttom.x) * f_coef;
					float fnew_y = l_buttom.y;
					float fnew_z = l_buttom.z + (r_top.z - l_buttom.z) * f_coef;
					destPos.x = fnew_x;
					destPos.y = fnew_y;
					destPos.z = fnew_z;
					//
					//pMap->FindNearestPos(fnew_x, fnew_y, fnew_z, &destPos.x, &destPos.y, &destPos.z, nullptr);
			
				}
			}
			else if (EMapAreaType_Circle == pAreaCfg->shapeType) //圆形[圆心，标志位置]
			{
				if (pAreaRefLoc->m_vecPos.size() >= 1)
				{
					Point3<float> fmid = pAreaRefLoc->m_vecPos.at(0);
					float littleRadiux = (float)(Random(0, (uint32_t)(pAreaRefLoc->m_radius * 1000))) / 1000.0f;
					float randomAngle = (float)(Random(0, 360 * 1000)) / 1000.0f;
					//
					float fnew_x = fmid.x + littleRadiux * cos(randomAngle);
					float fnew_y = fmid.y;
					float fnew_z = fmid.z + littleRadiux * sin(randomAngle);
					destPos.x = fnew_x;
					destPos.y = fnew_y;
					destPos.z = fnew_z;
					//
					//pMap->FindNearestPos(fnew_x, fnew_y, fnew_z, &destPos.x, &destPos.y, &destPos.z, nullptr);
				}
			}
			else
			{
				LogErrFmtPrint("MapLoactionCfg::RandPosInArea...shapetype error...areaId:%u,shapetype:%d, mapid:%u", areaId, pAreaCfg->shapeType, pAreaCfg->belongToSceneID);
			}
			//避免随机出来的点无效，这里取下附近的坐标
			pMap->FindNearestPos(destPos.x, destPos.z, destPos.y, &destPos.x, &destPos.z, &destPos.y, NULL);
		}
		else
		{
			LogErrFmtPrint("MapLoactionCfg::RandPosInArea...can not find map or area config...areaId:%u,mapid:%u ", areaId, pAreaCfg->belongToSceneID);
		}
	}
	else
	{
		LogErrFmtPrint("MapLoactionCfg::RandPosInArea...can not find area config...areaId:%u", areaId);
	}

	return destPos;
}

const CollectRefLocation *MapLoactionCfg::GetCollectRefLoc(uint32_t collectId)
{
	collectLocationMap::iterator iter = m_collectLoc.find(collectId);
	return (iter != m_collectLoc.end()) ? &iter->second : nullptr;
}

const PathRefLocation* MapLoactionCfg::GetPathRefLoc(uint32_t pathId)
{
	PathLocationMap::iterator iter = m_pathLoc.find(pathId);
	return (iter != m_pathLoc.end()) ? &iter->second : nullptr;
}
